﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Tassdar.Core.Helper;
using Tassdar.Framework.Interface.Base;
using Tassdar.Framework.Model.Base;

namespace Tassdar.Framework.Logic.Base
{
    public class SlimLogicBase<TSlimEntity> : ISlimLogicBase<TSlimEntity> where TSlimEntity : SlimEntityBase, new()
    {
        public SlimLogicBase(EFDbcontext dbcontext)
        {
            DbContext = dbcontext;
        }


        public SlimLogicBase()
        {
           
        }
        private EFDbcontext dbcontext;
        public EFDbcontext DbContext
        {
            get
            {
                if (dbcontext == null)
                {
                    dbcontext = DIHelper.ServiceProvider.GetService(typeof(EFDbcontext)) as EFDbcontext;
                    return dbcontext;
                }
                return dbcontext;
            }
            set { dbcontext = value; }
        }

        /// <summary>
        /// 获取指定实体的Queryable
        /// </summary>
        public IQueryable<TSlimEntity> Queryable
        {
            get { return DbContext.Set<TSlimEntity>(); }
        }

        /// <summary>
        /// 批量插入某个实体的数据
        /// </summary>
        /// <param name="entities">实体集合</param>
        /// <param name="save">是否保存</param>
        /// <param name="skipInvalid">是否中断验证</param>
        /// <returns></returns>
        public virtual ResultModel AddEntities(IList<TSlimEntity> entities, bool save = true, bool skipInvalid = true)
        {
            var validator = this as IValidate<TSlimEntity>;
            if (validator != null)
            {
                foreach (var item in entities)
                {
                    var valiRes = validator.Validate(item);
                    if (valiRes.result)
                    {
                        DbContext.Set<TSlimEntity>().Add(item);
                    }
                    else
                    {
                        if (!skipInvalid)
                        {
                            return new ResultModel(valiRes.message);
                        }
                    }
                }
            }
            else
            {
                DbContext.Set<TSlimEntity>().AddRange(entities);
            }
            if (save)
            {
                var res = Commit();
                if (res.Success)
                {
                    res.Data = entities.Select(x => x.Id).ToList();
                }
                return res; 
            }
            return new ResultModel();
        }

        /// <summary>
        /// 为某个实体在数据库中插入一条数据
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="save"></param>
        /// <returns></returns>
        public virtual ResultModel AddEntity(TSlimEntity entity, bool save = true)
        {
            //检测当前示例是否实现了数据验证接口，如果实现了，进行数据校验
            var validator = this as IValidate<TSlimEntity>;
            if (validator != null)
            {
                var valiRes = validator.Validate(entity);
                if (!valiRes.result)
                {
                    return new ResultModel(valiRes.message);
                }
            }
            
            DbContext.Add<TSlimEntity>(entity);
            if (save)
            {
                var res = Commit();
                //像EF提交持久化以后，把更改数据的ID返回去
                res.Data = entity.Id;
                return res;
            }
            return new ResultModel();
        }

        public virtual ResultModel AddOrEditEntity(TSlimEntity entity, bool save = true)
        {
            if (entity.Id != 0)
            {
                return AddEntity(entity, save);
            }
            else
            {
                return EditEntity(entity, save);
            }
        }

        public virtual ResultModel Commit()
        {
            var result = new ResultModel();
            try
            {
                var value_count = dbcontext.SaveChanges();
                result.Data = value_count;
                if (value_count > 0)
                {
                    result.Success = true;
                }
                else
                {
                    result.Success = false;
                    result.Message = "没有保存任何数据";
                }
            }
            catch (DbUpdateException db_Ex)
            {
                result.Success = false;
                result.Message = db_Ex.Message;
            }
            catch (Exception ex)
            {
                result.Success = false;
                result.Message = result.Message + ex.Message;               
            }
            return result;
        }

        public virtual ResultModel EditEntity(TSlimEntity entity, bool save = true)
        {
            var validator = this as IValidate<TSlimEntity>;
            if (validator != null)
            {
                var valiRes = validator.Validate(entity);
                if (!valiRes.result)
                {
                    return new ResultModel { Success = false, Message = valiRes.message };
                }
            }
            DbContext.Set<TSlimEntity>().Update(entity);
            if (save)
            {
                var res = Commit();
                return res;
            }
            return new ResultModel();
        }

        public virtual ResultModel ExcuteSql(string sql)
        {
            var res = DbContext.Database.ExecuteSqlCommand(sql);
            return new ResultModel { Success = true, Data = res };
        }

        public virtual int GetCount(Expression<Func<TSlimEntity, bool>> condition)
        {
            if (condition != null)
            {
                return this.Queryable.Count(condition);
            }
            else
            {
                return this.Queryable.Count();
            }
        }

        public virtual IList<TSlimEntity> GetEntities(Expression<Func<TSlimEntity, bool>> condition)
        {
            if (condition != null)
            {
                return this.Queryable.Where(condition).ToList();
            }
            return this.Queryable.ToList();
        }

        public virtual IList<TSlimEntity> GetEntities()
        {
            return this.Queryable.ToList();
        }

        public virtual IList<TSlimEntity> GetEntities<TVal>(Expression<Func<TSlimEntity, bool>> condition, Expression<Func<TSlimEntity, TVal>> orderBy, ListSortDirection direction)
        {
            IList<TSlimEntity> res = null;
            if (direction == ListSortDirection.Ascending)
            {
                res = Queryable.Where(condition).OrderBy(orderBy).ToList();
            }
            else
            {
                res = Queryable.Where(condition).OrderByDescending(orderBy).ToList();
            }
            return res;
        }

        public virtual IList<TSlimEntity> GetEntities<TVal>(out int rows, Expression<Func<TSlimEntity, bool>> condition = null, int pageIndex = 1, int pageSize = 20, Expression<Func<TSlimEntity, TVal>> orderBy = null, ListSortDirection direction = ListSortDirection.Descending)
        {
            var queryable = Queryable;
            if (condition != null)
            {
                queryable = queryable.Where(condition);
            }
            rows = queryable.Count();
            if (orderBy != null)
            {
                if (direction == ListSortDirection.Descending)
                    queryable = queryable.OrderByDescending(orderBy);
                else
                    queryable = queryable.OrderBy(orderBy);
            }
            else
            {
                if (direction == ListSortDirection.Descending)
                    queryable = queryable.OrderByDescending(x => x.Id);
                else
                    queryable = queryable.OrderBy(x => x.Id);
            }
            queryable = queryable.Skip((pageIndex - 1) * pageSize).Take(pageSize);
            var res = queryable.ToList();
            return res;
        }

        public virtual IList<TSlimEntity> GetEntities(int pageSize, int pageIndex, out int rows)
        {
            var res = GetEntities<int>(rows: out rows, condition: null, pageIndex: pageIndex, pageSize: pageSize, orderBy: x => x.Id, direction: ListSortDirection.Descending);
            return res;
        }

        public virtual TSlimEntity GetEntity(int id)
        {
            throw new NotImplementedException();
        }

        public virtual TSlimEntity GetEntity(Expression<Func<TSlimEntity, bool>> condition)
        {
            return Queryable.FirstOrDefault(condition);
        }

        public virtual IQueryable<TSlimEntity> GetQueryable()
        {
            return DbContext.Set<TSlimEntity>();
        }

        public virtual TVal GetValue<TVal>(Expression<Func<TSlimEntity, bool>> condition, Expression<Func<TSlimEntity, TVal>> selector)
        {
            var res = Queryable.Where(condition).Select(selector).FirstOrDefault();
            return res;
        }

        public virtual IList<TVal> GetValues<TVal>(Expression<Func<TSlimEntity, bool>> condition, Expression<Func<TSlimEntity, TVal>> selector)
        {
            var res = Queryable.Where(condition).Select(selector).ToList();
            return res;
        }

        public virtual ResultModel RemoveEntities(Expression<Func<TSlimEntity, bool>> condition, bool save = true)
        {
            var remove = DbContext.Set<TSlimEntity>().Where(condition);
            DbContext.Set<TSlimEntity>().RemoveRange(remove);
            if (save)
            {
                var res = Commit();
                return res;
            }
            else
                return new ResultModel();
        }

        public virtual ResultModel RemoveEntity(int id, bool save = true)
        {
            var remove = DbContext.Set<TSlimEntity>().Where(x => x.Id == id);
            DbContext.Set<TSlimEntity>().RemoveRange(remove);
            if (save)
            {
                var res = Commit();
                return res;
            }
            else
                return new ResultModel();
        }
    }
}
